﻿//  Copyright © Decebal Mihailescu 2013-2014
//  All rights reserved. This source code and binaries are distributed under
//  Microsoft Public PatternLicense (Ms-PL)
//  The latest code is available at http://VSDesignPatterns.codeplex.com

//  Redistributions of source code must retain the above copyright notice,
//  this list of conditions and the following disclaimer.
//  Redistributions in binary form must reproduce the above copyright notice,
//  this list of conditions and the following disclaimer in the documentation
//  and/or other materials provided with the distribution.

//  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
//  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
//  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
//  PURPOSE. IT CAN BE DISTRIBUTED FREE OF CHARGE AS LONG AS THIS HEADER
//  REMAINS UNCHANGED.
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;

namespace VSEmulator
{
    using Common;
    using DesignPatternsWizard;

    internal static class Program
    {
        private static IWizardWindow _wizWindow;
        private static bool Is64bitProcess { get { return Marshal.SizeOf(IntPtr.Zero) == 8; } }

        private static void _tabPageConfirm_Validating(object sender, CancelEventArgs e)
        {
        }

        private static void _tabPageEditPattern_Validating(object sender, CancelEventArgs e)
        {
        }

        private static void _tabPageSelection_Validated(object sender, EventArgs e)
        {
        }

        private static void _tabPageSelection_Validating(object sender, CancelEventArgs e)
        {
        }

        private static void CanGeneratePatternImpl(object sender, EventValidaton evval)
        {
            evval.Result = ResultEnum.Success;
            switch (evval.SelIndex)
            {
                case 2:
                    evval.ErrorMsg = "Some error";
                    evval.Result = evval.LangProvider.IsValidExtension(".*") ? ResultEnum.Success : ResultEnum.BadFileExtension;
                    foreach (var f in evval.Files)
                    {
                        string s = f;
                    }
                    break;

                default:
                    break;
            }
            evval.ErrorMsg = string.Format("Last Generation result: {0}", evval.Result);
            return;
        }

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        private static int Main(string[] args)
        {
            try
            {
                CultureInfo ci1 = new CultureInfo("de-DE");

                Thread.CurrentThread.CurrentCulture = ci1;
                Thread.CurrentThread.CurrentUICulture = ci1;
                CultureInfo ci = CultureInfo.CreateSpecificCulture("de");
                float assemblyVer1 = float.Parse("13.0", CultureInfo.InvariantCulture.NumberFormat);
                float assemblyVer = float.Parse("13,0", CultureInfo.InvariantCulture.NumberFormat);
                assemblyVer1 = float.Parse("13.0", ci.NumberFormat);
                assemblyVer = float.Parse("13,0", ci.NumberFormat);//NumberStyles.Float, ci);
            }
            catch (Exception ex)
            {
                string m = ex.Message;
            }
            /*
            using (RegistryKey destinationKey = Registry.CurrentUser.CreateSubKey(Utils.PlugInsHive + "BK", RegistryKeyPermissionCheck.ReadWriteSubTree))
            {
                //Open the sourceKey we are copying from
                using (RegistryKey sourceKey = Registry.CurrentUser.OpenSubKey(Utils.PlugInsHive, false))
                {
                    const string vsYear = "VS" + Utils.VSYear;
                    bool bRes = sourceKey.RecursiveCopyTo(destinationKey, ((_) => true), ((s) => s != vsYear));
                }
            }
            using (RegistryKey sourceKey = Registry.CurrentUser.OpenSubKey(Utils.PlugInsHive, true))
            {
              //  sourceKey.DeleteSubKeyTree("");
            }
            return 0;
            */

            string logPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "DesignPatternsEmulation_" + Utils.VSVersion + ".log");

            Logging.Instance.Init(3, 1024 * 1024, logPath);
            Logging.Instance.Log(3, "DesignPatterns Emulator version {5} initialized at {0}, Win ver = {1}, Crt dir: '{2}', CLR version ={3}, Is64BitProcess = {4}",
                DateTime.Now, Environment.OSVersion.Version, Environment.CurrentDirectory, RuntimeEnvironment.GetSystemVersion(), Is64bitProcess,
                Assembly.GetExecutingAssembly().GetName().Version);

            /*
            foreach (var lp in MEFController.Instance.GetLPInstatntiated(null))
            {
                lp.Value.RegisterLP(true, null);
                bool bcanGen = lp.Value.CanGenerate;
            }
            return 0;
            */
            /*
            dynamic shellApplication = Activator.CreateInstance(Type.GetTypeFromProgID("Shell.Application"));

            dynamic compressedFolderContents = shellApplication.NameSpace(@"C:\Sandbox\DesignPatterns\Misc\TemplateLibrary.zip").Items;

            if(!System.IO.Directory.Exists(@"c:\temp\unzip\"))
              System.IO.Directory.CreateDirectory(@"c:\temp\unzip\");
            dynamic destinationFolder = shellApplication.NameSpace(@"c:\temp\unzip\");
            destinationFolder.CopyHere(compressedFolderContents);

            if (args.Length == 0)
            {
                MessageBox.Show("You must give a project file as an arument!", "Missing Argument");
                return 1;
            }
            if(!File.Exists(args[0]))
            {
                MessageBox.Show("The file '" + args[0] +"' does not exists!", "Missing file");
                return -1;
            }
            */
            ProjectInfo prj = null;
            if (args.Length == 0)
            {
                prj = new ProjectInfo(CodeLangEnum.ManagedCpp, null);
                prj.FileName = @"C:\Sandbox\MultiProject\some filler";//args[0];//
            }
            else
            {
                IEnumerable<CodeLangEnum> langs = args.Select(a => a.ToLowerInvariant()).Select(s =>
                    {
                        if (s.EndsWith(".csproj")) return CodeLangEnum.CSharp;
                        if (s.EndsWith(".vbproj")) return CodeLangEnum.VB;
                        if (s.EndsWith(".vcproj")) return CodeLangEnum.NativeCpp;
                        return CodeLangEnum.None;
                    });
                if (langs.All(l => l == CodeLangEnum.None))
                    prj = new ProjectInfo(CodeLangEnum.CSharp, null);// no project in args
                else
                    prj = new ProjectInfo(langs.First(l => l != CodeLangEnum.None), null);
                prj.FileName = args[0];
            }

            prj.ProjectName = Path.GetFileNameWithoutExtension(prj.FileName);// "CSharpProj";
            prj.ProjectProperties = new Dictionary<string, string>(1);
            prj.ProjectProperties.Add("DefaultNamespace", prj.ProjectName);
            prj.ProjectProperties.Add("RootNamespace", prj.ProjectName);
            // make a managed CPP project

            if (prj.CodeLang == CodeLangEnum.NativeCpp)
            {
                prj.ProjectProperties.Add("keyword", "ManagedCProj");
                prj.CodeLang = CodeLangEnum.ManagedCpp;
            }
            Application.EnableVisualStyles();

            WizardForm frm = new WizardForm(prj);
            frm.VSWindow = null;
            _wizWindow = frm;

            prj.CanUpdateVSProject += new CanUpdateVSProjectDelegate(CanGeneratePatternImpl);
            prj.UpdateVSProject += new UpdateVSProjectDelegate(wizForm_GeneratePattern);
            _wizWindow.WizardWindowClosed += new WizardWindowClosedDelegate(wiz_WizardWindowClosed);
            _wizWindow.WizardWindowClosed += new WizardWindowClosedDelegate(wizForm_WizardWindowClosed);
            Application.Run(_wizWindow as Form);
            return 0;
        }
        private static void wiz_WizardWindowClosed(object sender, EventWizardWindowClosed evclosed)
        {
            return;
        }

        private static void wizForm_CanGeneratePattern(IServiceProvider isp, EventValidaton evval)
        {/*
            evval.ErrorMsg = null;
            evval.Result = ResultEnum.UnknownError;
            switch (evval.SelIndex)
            {
                case 2:

                    if (isp == null)
                    {
                        evval.ErrorMsg = "The Sender is null or not a IServiceProvider";
                        Logging.Instance.Log(2, "In Connect.wizForm_CanGeneratePattern " + evval.ErrorMsg);
                        return;
                    }
                    IProjectInfo inf = isp.GetAsService<IProjectInfo>();
                    Project proj = _applicationObject.GetProjectbyInfo(inf);

                    if (proj == null)
                    {
                        evval.ErrorMsg = "Can not get the project reference for " + ((inf == null) ? "null IprojectInfo" : inf.FileName);
                        Logging.Instance.Log(2, "In Connect.wizForm_CanGeneratePattern " + evval.ErrorMsg);
                        return;
                    }
                    ILanguageProvider lp = (evval.LangProvider == null) ? inf.GetAsService<ILanguageProvider>() : evval.LangProvider;
                    if (evval.Files == null)
                    {
                        evval.Result = ResultEnum.Success;
                        Logging.Instance.Log(2, "In Connect.wizForm_CanGeneratePattern No Files found");
                        return;
                    }
                    foreach (string newfile in evval.Files)
                    {
                        evval.Result = CanAddToProject(proj, newfile, lp, out evval.ErrorMsg);
                        if (evval.Result != ResultEnum.Success)
                        {
                            Logging.Instance.Log(2, "In Connect.wizForm_CanGeneratePattern failed to add file" + newfile);
                            break;
                        }
                    }

                    break;

                default:
                    evval.Result = ResultEnum.Success;
                    break;
            }
          */
        }

        private static void wizForm_GeneratePattern(object sender, EventGeneration evtg)
        {
            evtg.Result = evtg.LangProvider.IsValidExtension(".*") ? ResultEnum.Success : ResultEnum.BadFileExtension;

            foreach (var f in evtg.Files)
            {
                string s = f.itemName;
            }
            evtg.ErrorMsg = string.Format("Last Generation result: {0}", evtg.Result);
        }
        private static void wizForm_WizardWindowClosed(object sender, EventWizardWindowClosed evclosed)
        {
            if (_wizWindow != null)
            {
                IProjectInfo prjinf = _wizWindow.GetAsService<IProjectInfo>();
                if (prjinf != null)
                {
                    prjinf.UpdateVSProject -= new UpdateVSProjectDelegate(wizForm_GeneratePattern);
                    prjinf.CanUpdateVSProject -= new CanUpdateVSProjectDelegate(wizForm_CanGeneratePattern);

                    if (_wizWindow.IsRestarting)//to debug use !
                    {
                        string file = Application.ExecutablePath;
                        if (string.Compare(Path.GetFileName(Application.ExecutablePath), "devenv.exe", true) != 0)//for testing
                        {                // Launch itself as with elevated role
                            ProcessStartInfo proc = new ProcessStartInfo();
                            proc.UseShellExecute = true;
                            proc.WorkingDirectory = Environment.CurrentDirectory;
                            proc.FileName = file;
                            proc.Arguments = Environment.GetCommandLineArgs().Skip(1).Aggregate((workingSentence, next) => (workingSentence + " \"" + next) + '"').TrimStart();
                            if (proc.Arguments.Contains(' '))
                            {
                                proc.Arguments = "\"" + proc.Arguments + "\"";
                            }
                            proc.Verb = "runas";
                            RegistryKey reg = Registry.CurrentUser.CreateSubKey(Common.Utils.AppHive, RegistryKeyPermissionCheck.Default);
                            if (reg != null)
                            {
                                reg.SetValue("SolutionName", proc.Arguments ?? "nothing", RegistryValueKind.String);
                                reg.Close();
                            }
                            Process.Start(proc);
                        }
                        //// Launch itself as with elevated role
                        //ProcessStartInfo proc = new ProcessStartInfo();
                        //proc.UseShellExecute = true;
                        //proc.WorkingDirectory = Environment.CurrentDirectory;
                        //proc.FileName = Utils.VSPath;

                        //proc.Arguments = "\"" + file + "\"";
                        //proc.Verb = "runas";
                        //System.Diagnostics.Process.Start(proc);

                        return;
                    }
                }
                _wizWindow.Dispose();
            }
            _wizWindow = null;
        }
    }
}